package org.ielse.frame;

import static org.ielse.frame.util.BaseUtil.inputStreamToString;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

import org.ielse.frame.model.AppSettings;
import org.ielse.frame.t.cache.DiskLruCacheUtil;
import org.ielse.frame.t.volley.GsonRequest;
import org.ielse.frame.t.volley.MultipartEntity;
import org.ielse.frame.t.volley.MultipartInfo;
import org.ielse.frame.t.volley.MultipartRequest;
import org.ielse.frame.util.BaseUtil;
import org.ielse.frame.util.LogUtil;
import org.ielse.frame.util.NetworkUtil;
import org.ielse.frame.util.SpfsUtil;
import org.ielse.frame.view.PictureLayout;
import org.ielse.frame.view.ShinyLayout;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.app.FragmentActivity;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.inputmethod.InputMethodManager;
import android.widget.TextView;
import android.widget.Toast;

import com.android.volley.AuthFailureError;
import com.android.volley.Request.Method;
import com.android.volley.RequestQueue.RequestFilter;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.Response.Listener;
import com.android.volley.VolleyError;
import com.google.gson.Gson;

public class BaseActivity extends FragmentActivity implements ViewCallback {
	
	private static final int REQUEST_CODE_CAPTURE_PICTURE = 1204;
	private static final int REQUEST_CODE_PICK_IMAGE = 1205;
	private File fCapturePicture;

	protected ShinyLayout layContentWrapper;
	protected PictureLayout layPicture;

	protected DiskLruCacheUtil diskLruCacheUtil;
	protected Gson gson;
	protected RequestQueue requestQueue;
	protected boolean useDefaultTransitionAnim = true;
	protected Context context;
	protected AppSettings appSettings;
	
	private Thread uploadThread= new Thread();

	@Override protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		LogUtil.d(getClass().getSimpleName() + " onCreate()");
		ActivityCollector.addActivity(this);
		requestQueue = App.i().getRequestQueue();
		diskLruCacheUtil = App.i().getDiskLruCacheUtil();
		gson = App.i().getGson();
		appSettings = App.i().getAppSettings();

		context = this;
		getWindow().setBackgroundDrawableResource(android.R.color.white);
	}

	@Override protected void onResume() {
		super.onResume();
		LogUtil.d(getClass().getSimpleName() + " onResume()");
	}

	@Override protected void onDestroy() {
		super.onDestroy();
		ActivityCollector.removeActivity(this);
		LogUtil.d(getClass().getSimpleName() + " onDestroy()");
	}

	@Override public void setContentView(int layoutResID) {
		setContentView(inflate(layoutResID));
	}

	@Override public void setContentView(View view) {
		setContentView(view, null);
	}

	@Override public void setContentView(View view, ViewGroup.LayoutParams params) {
		layContentWrapper = new ShinyLayout(this);
		layContentWrapper.setDispatchTouchEventListener(new ShinyLayout.DispatchTouchEventListener() {
			@Override public void onDispatchTouchEvent(MotionEvent ev) {
				switch (ev.getAction()) {
				case MotionEvent.ACTION_UP:
					hideSoftInputFromWindow();
					break;
				}
			}
		});

		layPicture = new PictureLayout(this);
		layPicture.setVisibility(View.GONE);
		layContentWrapper.addView(layPicture, 0);

		layContentWrapper.addView(view, 0);

		if (params != null) {
			super.setContentView(layContentWrapper, params);
		}
		else {
			super.setContentView(layContentWrapper);
		}
	}

	@Override public void startActivity(Intent intent) {
		super.startActivity(intent);
		if (useDefaultTransitionAnim) {
			overridePendingTransition(R.anim.slide_right_enter, R.anim.slide_left_exit);
		}
	}

	@Override public void finish() {
		super.finish();
		if (useDefaultTransitionAnim && ActivityCollector.size() > 1) {
			overridePendingTransition(R.anim.slide_left_enter, R.anim.slide_right_exit);
		}
	}

	@SuppressWarnings({ "unchecked", "unused" }) private <T extends View> T findView(int id) {
		return (T) findViewById(id);
	}

	protected void hideSoftInputFromWindow() {
		if (this.getCurrentFocus() != null) {
			((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(this.getCurrentFocus()
					.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
		}
	}

	protected void showToast(int resId) {
		showToast(getString(resId));
	}

	protected void showToast(String text) {
		Toast.makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show();
	}

	protected void startActivity(Class<?> targetActivity, Object... params) {
		startActivity(targetActivity, BaseUtil.initBundle(params));
	}

	protected void startActivity(Class<?> targetActivity, Bundle bundle) {
		Intent intent = new Intent(this, targetActivity);
		if (bundle != null) {
			intent.putExtras(bundle);
		}
		startActivity(intent);
	}

	protected <T> void request(int method, final String url, final Map<String, String> params, final Class<T> clazz,
			final VolleyListenerAdapter<T> listener) {
		request(method, url, params, clazz, listener, false);
	}

	protected <T> void request(int method, final String url, final Map<String, String> params, final Class<T> clazz,
			final VolleyListenerAdapter<T> listener, final boolean useCache) {
		GsonRequest<T> gsonRequest = new GsonRequest<T>(Method.POST, url, clazz, new Response.Listener<T>() {
			@Override public void onResponse(T response) {
				if (response != null) {
					if (listener != null) listener.onResponse(response, true);

					String respInfo = gson.toJson(response);
					LogUtil.i("onResponse() " + url + "\n" + respInfo);
					if (useCache) diskLruCacheUtil.write(url + "#" + params, new ByteArrayInputStream(respInfo.getBytes()));
				}
				else {
					listener.onErrorResponse(new VolleyError("empty response"));
				}
			}
		}, new Response.ErrorListener() {
			@Override public void onErrorResponse(VolleyError error) {
				LogUtil.e("onErrorResponse() " + url + "\n" + error.getMessage());
				if (useCache) {
					InputStream cache = diskLruCacheUtil.read(url + "#" + params);
					if (cache != null) {
						String cacheInfo = inputStreamToString(cache);
						LogUtil.d("use last request cache " + url + "\n" + cacheInfo);
						if (listener != null) listener.onResponse(gson.fromJson(cacheInfo, clazz), false);
						return;
					}
				}

				if (listener != null) listener.onErrorResponse(error);
			}
		}) {
			@Override protected Map<String, String> getParams() throws AuthFailureError {
				return params;
			}
		};

		LogUtil.d("request() " + url + "\n" + params);
		requestQueue.add(gsonRequest);
	}

	protected void upload(final String url, final List<MultipartInfo> params, final VolleyListenerAdapter<String> listener) {
		new Thread(new Runnable() {
			@Override public void run() {
				MultipartRequest multipartRequest = new MultipartRequest(url, new Listener<String>() {
					@Override public void onResponse(final String response) {
						runOnUiThread(new Runnable() {
							@Override public void run() {
								LogUtil.i("onResponse() " + url + "\n" + response);
								if (listener != null) listener.onResponse(response, true);
							}
						});
					}
				}, new Response.ErrorListener() {
					@Override public void onErrorResponse(final VolleyError error) {
						runOnUiThread(new Runnable() {
							@Override public void run() {
								LogUtil.e("onErrorResponse() " + url + "\n" + error.getMessage());
								if (listener != null) listener.onErrorResponse(error);
							}
						});
					}
				});

				if (params != null && params.size() > 0) {
					MultipartEntity multipartEntity = multipartRequest.getMultiPartEntity();
					for (MultipartInfo multipartInfo : params) {
						switch (multipartInfo.type) {
						case MultipartInfo.TYPE_HEADER:
							multipartRequest.addHeader(multipartInfo.key, (String) multipartInfo.value);
							break;
						case MultipartInfo.TYPE_TEXT:
							multipartEntity.addStringPart(multipartInfo.key, (String) multipartInfo.value);
							break;
						case MultipartInfo.TYPE_BINARY:
							// 耗时操作 阻塞线程
							multipartEntity.addBinaryPart(multipartInfo.key, (byte[]) multipartInfo.value);
							break;
						case MultipartInfo.TYPE_FILE:
							multipartEntity.addFilePart(multipartInfo.key, new File((String) multipartInfo.value));
							break;
						}
					}
				}

				LogUtil.d("upload() " + url + "\n" + params);
				requestQueue.add(multipartRequest);
			}
		}).start();
	}

	public class VolleyListenerAdapter<T> {
		public void onResponse(T response, boolean isFresh) {
		}

		public void onErrorResponse(VolleyError error) {
			TextView txInfo = new TextView(context);
			txInfo.setText(NetworkUtil.isNoInternet() ? R.string.error_net : R.string.error_request);
			txInfo.setTextColor(0xffffffff);
			txInfo.setBackgroundColor(0xff0d7dd1);
			final int spacing = BaseUtil.dipToPx(8);
			txInfo.setPadding(spacing * 2, spacing, spacing * 2, spacing);
			txInfo.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
			Toast t = new Toast(context);
			t.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 0);
			t.setDuration(Toast.LENGTH_LONG);
			t.setView(txInfo);
			t.show();
		}
	}

	@SuppressWarnings("unchecked") public <T extends View> T inflate(int resource) {
		return (T) LayoutInflater.from(this).inflate(resource, null);
	}

	@SuppressWarnings("unchecked") public <T extends View> T inflate(int resource, ViewGroup root, boolean attachToRoot) {
		return (T) LayoutInflater.from(this).inflate(resource, root, attachToRoot);
	}

	protected void startService(Class<?> service) {
		Intent intent = new Intent(this, service);
		startService(intent);
	}

	protected void stopService(Class<?> service) {
		Intent intent = new Intent(this, service);
		stopService(intent);
	}

	protected void bindService(Class<?> service, ServiceConnection conn) {
		Intent intent = new Intent(this, service);
		bindService(intent, conn, BIND_AUTO_CREATE);
	}

	protected void registerReceiver(BroadcastReceiver receiver, String... actions) {
		IntentFilter filter = new IntentFilter();
		for (String act : actions) {
			filter.addAction(act);
		}
		registerReceiver(receiver, filter);
	}

	@Override public final void onBackPressed() {
		if (View.VISIBLE == layPicture.getVisibility()) {
			layPicture.hiddenPictrue();
		}
		else if (!onChildBackPressed()) {
			super.onBackPressed();
		}
	}

	/**
	 * when back pressed,this method will invoke<br>
	 * child impl
	 */
	protected boolean onChildBackPressed() {
		return false;
	}

	/** child impl */
	public void onViewCallback(int action, Object... args) {
		switch (action) {
		case ACTION_LAY_PICTURE_SAVE_TO_ALBUM:
			Uri data = Uri.parse("file://" + (String) args[0]);
			sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, data));
			showToast(R.string.frame_saved_photo_to_album);
			break;
		}
	};

	public void openCamera() {
		Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
		fCapturePicture = new File(getExternalCacheDir(), C.settings.PICTURE_NAME + System.currentTimeMillis() + ".jpg");
		intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(fCapturePicture));
		startActivityForResult(intent, REQUEST_CODE_CAPTURE_PICTURE);
	}

	public void openPhotos() {
		if (openPhotosNormal() && openPhotosBrowser() && openPhotosFinally())
		;
	}

	private boolean openPhotosNormal() {
		Intent intent = new Intent(Intent.ACTION_PICK);
		intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
		try {
			startActivityForResult(intent, REQUEST_CODE_PICK_IMAGE);
		} catch (android.content.ActivityNotFoundException e) {
			return true;
		}
		return false;
	}

	private boolean openPhotosBrowser() {
		Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
		intent.setType("image/*");
		Intent wrapperIntent = Intent.createChooser(intent, null);
		try {
			startActivityForResult(wrapperIntent, REQUEST_CODE_PICK_IMAGE);
		} catch (android.content.ActivityNotFoundException e1) {
			return true;
		}
		return false;
	}

	private boolean openPhotosFinally() {
		showToast(R.string.frame_no_photo_album);
		return false;
	}

	@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (requestCode == REQUEST_CODE_PICK_IMAGE) {
			if (resultCode == RESULT_OK) {
				String[] filePathColumn = { MediaStore.Images.Media.DATA };
				Cursor cursor = context.getContentResolver().query(data.getData(), filePathColumn, null, null, null);
				cursor.moveToFirst();
				int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
				String picturePath = cursor.getString(columnIndex);
				cursor.close();

				LogUtil.d("openPhotos pick_image\n" + picturePath);
				onViewCallback(ACTION_QUERY_IMAGE, picturePath);
			}
		}
		else if (requestCode == REQUEST_CODE_CAPTURE_PICTURE) {
			if (resultCode == RESULT_OK) {
				LogUtil.d("openCamera capture_picture\n" + fCapturePicture.getAbsolutePath());
				onViewCallback(ACTION_QUERY_IMAGE, fCapturePicture.getAbsolutePath());
				SpfsUtil.remove(C.app.CAPTURE_PICTURE);
			}
		}
	}

	@Override protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		if (fCapturePicture != null) SpfsUtil.write(C.app.CAPTURE_PICTURE, fCapturePicture.getAbsolutePath());
	}

	@Override protected void onRestoreInstanceState(Bundle savedInstanceState) {
		super.onRestoreInstanceState(savedInstanceState);
		String picturePath = SpfsUtil.readString(C.app.CAPTURE_PICTURE);
		if (!TextUtils.isEmpty(picturePath)) fCapturePicture = new File(picturePath);
	}
}
